package com.wwcom.darteagle;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.os.Bundle;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Toast;

import com.androidplot.Plot;
import com.androidplot.xy.SimpleXYSeries;
import com.androidplot.series.XYSeries;
import com.androidplot.ui.AnchorPosition;
import com.androidplot.ui.SizeLayoutType;
import com.androidplot.ui.SizeMetrics;
import com.androidplot.xy.*;
import com.wwcom.darteagle.data.DartEagleDatabase;
import com.wwcom.darteagle.model.DartStats;
import com.wwcom.darteagle.model.Player;
import com.wwcom.darteagle.util.Global;

import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
 
/**
 * The simplest possible example of using AndroidPlot to plot some data.
 */
public class PlayerStatsActivity extends Activity implements OnTouchListener
{
	public static final String PLAYER_NAMES= "playerNames";
	public static final String STAT_ID= "statId";
    private XYPlot mySimpleXYPlot;
	private long minXY_x, maxXY_x;
	private float minXY_y,maxXY_y;
	
	@Override
    public void onCreate(Bundle savedInstanceState)
    {
 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.playerstats);
 
        // initialize our XYPlot reference:
        mySimpleXYPlot = (XYPlot) findViewById(R.id.mySimpleXYPlot);
 
        //get player names
        Bundle extras= getIntent().getExtras();
        if (extras == null) 
        	throw new RuntimeException("PlayerStatsActivity::onCreate - no players specified");

        DartEagleDatabase db= new DartEagleDatabase(this);

        String[] playerNames= TextUtils.split(extras.getString(PLAYER_NAMES),"#,#");        
        List<Player> players= new ArrayList<Player>(playerNames.length);
        for (String s : Arrays.asList(playerNames)) {
        	Player p= db.getPlayer(s);
        	players.add(p);
        	Log.d("PlayerStatsActivity","Player: "+s);
        }
        int statId= (int)extras.getLong(STAT_ID);
        
        //get statistics
        //restrict to one month previous if not premium
        long dateThresh= 0;        
        if (Global.APP_PREMIUM) {
        	Calendar calendar = Calendar.getInstance();
        	calendar.add( Calendar.MONTH ,  -1 );
        	dateThresh= calendar.getTime().getTime();
        }
        	
        
        //List< List<Number> > allPlayerStats= new ArrayList< List<Number> >(players.size());
        int playerInd= 0;
        float maxRange= 0.0f;
        float minRange= Float.MAX_VALUE;
        long maxDomain= 0;
        long minDomain= Long.MAX_VALUE;
        boolean shownToast= false;
        for (Player p : players) {
        	List<DartStats> dsList= db.getPlayerDartStats(p);
        	List<Number> playerStats= new ArrayList<Number>(dsList.size());            
        	List<Number> statDates= new ArrayList<Number>(dsList.size());            
        	for (DartStats ds : dsList) {
        		long domainVal= (long)ds.getMatchInfo().getDate();
        		if (domainVal < dateThresh) { //don't show all data unless premium
        			if (!shownToast) {
        	    		Toast t = Toast.makeText(this, getString(R.string.playerstats_premium_upgrade), Toast.LENGTH_LONG);
        	    		t.setGravity(Gravity.CENTER|Gravity.CENTER, 0, 0);
        	    		t.show();
        	    		shownToast= true;
        			}
        			continue;
        		}
        		if (domainVal > maxDomain)
        			maxDomain= domainVal;
        		if (domainVal < minDomain)
        			minDomain= domainVal;
        		statDates.add(domainVal);
        		float rangeVal= -1.0f;
        		switch (statId) {
        			case DartStats.AVERAGE:
        				Log.d("PlayerStatsActivity","Average: "+ds.getAverage());
        				rangeVal= ds.getAverage()*3.0f;
        				break;
        			case DartStats.FIRST9AVERAGE:
        				rangeVal= ds.getFirst9Average()*3.0f;
                		break;
        			case DartStats.HIGHESTSCORE:
        				rangeVal= ds.getHighestScore();
                		break;
        			case DartStats.PLUS60:
        				rangeVal= ds.getPlus60();
                		break;
        			case DartStats.PLUS100:
        				rangeVal= ds.getPlus100();
                		break;
        			case DartStats.PLUS140:
        				rangeVal= ds.getPlus140();
                		break;
        			case DartStats.PLUS180:
        				rangeVal= ds.getPlus180();
                		break;
        			case DartStats.DOUBLES:
        				rangeVal= ds.getDoublePercentage();
                		break;
        			case DartStats.CHECKOUTS:
        				rangeVal= ds.getCheckoutPercentage();
                		break;
        			case DartStats.HIGHESTCHECKOUT:
        				rangeVal= ds.getHighestCheckout();
                		break;
        			case DartStats.PLUS50CHECKOUT:
        				rangeVal= ds.getPlus50Checkout();
                		break;
        			case DartStats.PLUS100CHECKOUT:
        				rangeVal= ds.getPlus100Checkout();
                		break;                		
        			case DartStats.ACCURACY20:
        				rangeVal= ds.getAccuracy20Rating();
                		break;                		
        			case DartStats.ACCURACY19:
        				rangeVal= ds.getAccuracy19Rating();
                		break;                		
        			case DartStats.PERCENTAGE20:
        				rangeVal= ds.getAccuracy20Percentage();
                		break;                		
        			case DartStats.PERCENTAGE19:
        				rangeVal= ds.getAccuracy19Percentage();
                		break;                		
        		}
        		if (rangeVal > maxRange)
        			maxRange= rangeVal;
        		if (rangeVal < minRange)
        			minRange= rangeVal;
				playerStats.add(rangeVal);
        		
        	}
        	//allPlayerStats.add(playerStats);
        	
            XYSeries series1 = new SimpleXYSeries(
            		statDates,
                    playerStats,          
                    p.getName());                             // Set the display title of the series

            float hue= (float)playerInd/(float)players.size() * 360f;
            LineAndPointFormatter series1Format = new LineAndPointFormatter(
            		Color.HSVToColor(new float[]{hue, 1.0f, 1.0f}),                   // line color
            		Color.HSVToColor(new float[]{hue, 0.5f, 1.0f}),                   // point color
                    null); // fill color (none)
            //series1Format.getLinePaint().setStrokeWidth(3f);
     
            // add a new series' to the xyplot:
            mySimpleXYPlot.addSeries(series1, series1Format);
            
            playerInd++;
        }
        db.close();
        
        
        Paint paint = mySimpleXYPlot.getLegendWidget().getTextPaint();
        paint.setTextSize(18);
        mySimpleXYPlot.getLegendWidget().setSize(
        		new SizeMetrics(20.0f,SizeLayoutType.ABSOLUTE,0.8f,SizeLayoutType.RELATIVE)
        );
        mySimpleXYPlot.getLegendWidget().setIconSizeMetrics(
        		new SizeMetrics(16.0f,SizeLayoutType.ABSOLUTE,16.0f,SizeLayoutType.ABSOLUTE)
        );
        // reposition the legend:
        mySimpleXYPlot.position(
                mySimpleXYPlot.getLegendWidget(),
                0.5f,
                XLayoutStyle.RELATIVE_TO_LEFT,
                -20,
                YLayoutStyle.ABSOLUTE_FROM_BOTTOM,
                AnchorPosition.BOTTOM_MIDDLE);
        
        mySimpleXYPlot.setTitle(getString(R.string.playerstats_player_stats));
        Paint titlePaint = mySimpleXYPlot.getTitleWidget().getLabelPaint();
        titlePaint.setTextSize(24);
        mySimpleXYPlot.getTitleWidget().setSize(
        		new SizeMetrics(24.0f,SizeLayoutType.ABSOLUTE,1.0f,SizeLayoutType.RELATIVE)
        );
        // reposition the title:
        mySimpleXYPlot.position(
                mySimpleXYPlot.getTitleWidget(),
                0.5f,
                XLayoutStyle.RELATIVE_TO_LEFT,
                -10,
                YLayoutStyle.ABSOLUTE_FROM_TOP,
                AnchorPosition.TOP_MIDDLE);
                
        mySimpleXYPlot.setBorderStyle(Plot.BorderStyle.NONE, null, null);
        //margins
        mySimpleXYPlot.getGraphWidget().setMarginTop(16);
        mySimpleXYPlot.getGraphWidget().setMarginBottom(16);
        mySimpleXYPlot.getGraphWidget().setMarginRight(10);
        mySimpleXYPlot.getGraphWidget().setMarginLeft(24);
        mySimpleXYPlot.setPlotPaddingTop(10);
        mySimpleXYPlot.setPlotMarginBottom(32);
        //background colors
        Paint backgroundPaint= new Paint();
        backgroundPaint.setARGB(255, 0, 0, 0);
        mySimpleXYPlot.setBackgroundPaint(backgroundPaint);
        mySimpleXYPlot.getGraphWidget().setBackgroundPaint(backgroundPaint);
        mySimpleXYPlot.getGraphWidget().setGridBackgroundPaint(backgroundPaint);
        //yaxis
        Paint rangePaint= mySimpleXYPlot.getGraphWidget().getRangeLabelPaint();
        rangePaint.setTextSize(16);
        rangePaint.setColor(Color.WHITE);
        rangePaint= mySimpleXYPlot.getRangeLabelWidget().getLabelPaint();
        rangePaint.setTextSize(16);
        rangePaint.setColor(Color.WHITE);
        rangePaint= mySimpleXYPlot.getGraphWidget().getRangeOriginLabelPaint();
        rangePaint.setTextSize(16);
        rangePaint.setColor(Color.WHITE);        
        rangePaint= mySimpleXYPlot.getGraphWidget().getRangeOriginLinePaint();
        rangePaint.setStrokeWidth(2);
        float rangePad= (maxRange - minRange)*0.05f;
        if (rangePad==0f) {
        	rangePad= 1f;
        }
        minRange= (float) Math.floor(minRange-rangePad);
        if (minRange < 0f)
        	minRange= 0f;
        maxRange= (float) Math.ceil(maxRange+rangePad);
        mySimpleXYPlot.setRangeBoundaries(minRange, maxRange, BoundaryMode.FIXED);
        mySimpleXYPlot.setRangeStep(XYStepMode.SUBDIVIDE, 16.0);
        String label= this.getString(DartStats.STATS_NAMES[statId]);
        label= label.substring(0,label.length()-1);  //get rid of :
        mySimpleXYPlot.setRangeLabel(label);        
        //x axis
        Paint domainPaint= mySimpleXYPlot.getGraphWidget().getDomainLabelPaint();
        domainPaint.setTextSize(16);
        domainPaint.setColor(Color.WHITE);
        domainPaint= mySimpleXYPlot.getDomainLabelWidget().getLabelPaint();
        domainPaint.setTextSize(16);
        domainPaint.setColor(Color.WHITE);
        domainPaint= mySimpleXYPlot.getGraphWidget().getDomainOriginLabelPaint();
        domainPaint.setTextSize(16);
        domainPaint.setColor(Color.WHITE);        
        domainPaint= mySimpleXYPlot.getGraphWidget().getDomainOriginLinePaint();
        domainPaint.setStrokeWidth(2);
        mySimpleXYPlot.setDomainLabel("Date");
        long domainPad= (long)((float)(maxDomain - minDomain)*0.05f);
        mySimpleXYPlot.setDomainBoundaries(minDomain-domainPad, 
        		maxDomain+domainPad, BoundaryMode.FIXED);
        mySimpleXYPlot.setDomainStep(XYStepMode.SUBDIVIDE, 4.0);
        
        
 
        // reduce the number of range labels
        mySimpleXYPlot.setTicksPerRangeLabel(3);
         
        // by default, AndroidPlot displays developer guides to aid in laying out your plot.
        // To get rid of them call disableAllMarkup():
        mySimpleXYPlot.disableAllMarkup();

    	//Set of internal variables for keeping track of the boundaries
		mySimpleXYPlot.calculateMinMaxVals();
		minXY_x= mySimpleXYPlot.getCalculatedMinX().longValue();
		minXY_y= mySimpleXYPlot.getCalculatedMinY().floatValue();
		maxXY_x= mySimpleXYPlot.getCalculatedMaxX().longValue();
		maxXY_y= mySimpleXYPlot.getCalculatedMaxY().floatValue();
        
		setDomainFormatter();
        
        mySimpleXYPlot.setOnTouchListener(this);
        mySimpleXYPlot.redraw();
        

        mySimpleXYPlot.setRangeValueFormat(new Format() {
			private static final long serialVersionUID = 1L;

			@Override
    		public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
    			// our timestamps are in milliseconds and SimpleDateFormat
    			int value = ((Number) obj).intValue();
    			return new StringBuffer(Integer.toString(value));
    		}

    		@Override
    		public Object parseObject(String source, ParsePosition pos) {
    			return null;

    		}
    	});
    }

    private void setDomainFormatter()
    {
        final Context context= this;
        long dateRange= maxXY_x - minXY_x;
        long oneHour= 1000l*60l*60l;
        if (dateRange < oneHour*24l) {  //less than one day
        	mySimpleXYPlot.setDomainValueFormat(new Format() {
				private static final long serialVersionUID = 1L;

				@Override
        		public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
        			// our timestamps are in milliseconds and SimpleDateFormat
        			long timestamp = ((Number) obj).longValue();
        			Date date = new Date(timestamp);
        			return new StringBuffer(DateFormat.getTimeFormat(context).format(date));
        		}

        		@Override
        		public Object parseObject(String source, ParsePosition pos) {
        			return null;

        		}
        	});     
        	
        } else if (dateRange < oneHour*24l*30l) {  //less than one month
            	mySimpleXYPlot.setDomainValueFormat(new Format() {
					private static final long serialVersionUID = 1L;

					@Override
            		public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
            			// our timestamps are in milliseconds and SimpleDateFormat
            			long timestamp = ((Number) obj).longValue();
            			Date date = new Date(timestamp);
            			SimpleDateFormat simpleDateFormat =
            			        new SimpleDateFormat("dd MMM",Locale.getDefault());
            			return new StringBuffer(simpleDateFormat.format(date));
            		}

            		@Override
            		public Object parseObject(String source, ParsePosition pos) {
            			return null;

            		}
            	});     
        } else {
        	mySimpleXYPlot.setDomainValueFormat(new Format() {
				private static final long serialVersionUID = 1L;

				@Override
        		public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
        			// our timestamps are in milliseconds and SimpleDateFormat
        			long timestamp = ((Number) obj).longValue();
        			Date date = new Date(timestamp);
        			SimpleDateFormat simpleDateFormat =
        			        new SimpleDateFormat("MMM yy",Locale.getDefault());
        			return new StringBuffer(simpleDateFormat.format(date));
        		}

        		@Override
        		public Object parseObject(String source, ParsePosition pos) {
        			return null;

        		}
        	});     
        }

    }
    
    // Definition of the touch states
 	static final int NONE = 0;
 	static final int ONE_FINGER_DRAG = 1;
 	static final int TWO_FINGERS_DRAG = 2;
 	int mode = NONE;

 	PointF firstFinger;
 	float lastScrolling;
 	float distBetweenFingers;
 	float lastZooming;

 	public boolean onTouch(View arg0, MotionEvent event) {
 		switch (event.getAction() & MotionEvent.ACTION_MASK) {
 		case MotionEvent.ACTION_DOWN: // Start gesture
 			firstFinger = new PointF(event.getX(), event.getY());
 			mode = ONE_FINGER_DRAG;
 			break;
 		case MotionEvent.ACTION_POINTER_DOWN: // second finger
 			distBetweenFingers = spacing(event);
 			// the distance check is done to avoid false alarms
 			if (distBetweenFingers > 5f) {
 				mode = TWO_FINGERS_DRAG;
 			}
 			break;
 			
 		case MotionEvent.ACTION_UP:
 		case MotionEvent.ACTION_POINTER_UP:
 			mode= NONE;
 			break;
 		case MotionEvent.ACTION_MOVE:
 			if (mode == ONE_FINGER_DRAG) {
 				PointF oldFirstFinger=firstFinger;
 				firstFinger=new PointF(event.getX(), event.getY());
 				lastScrolling=oldFirstFinger.x-firstFinger.x;
 				scrollX(lastScrolling);
 				lastScrolling=oldFirstFinger.y-firstFinger.y;
 				Log.d("PlayerStatsActivity","lastScrolling: "+lastScrolling);
 				scrollY(lastScrolling);
 				mySimpleXYPlot.setDomainBoundaries(minXY_x, maxXY_x, BoundaryMode.FIXED);
 				mySimpleXYPlot.setRangeBoundaries(minXY_y, maxXY_y, BoundaryMode.FIXED);
 				setDomainFormatter();
 				mySimpleXYPlot.redraw();

 			} else if (mode == TWO_FINGERS_DRAG) {
 				float oldDist= distBetweenFingers; 
 				distBetweenFingers=spacing(event);
 				lastZooming=oldDist/distBetweenFingers;
 				zoom(lastZooming);
 				mySimpleXYPlot.setDomainBoundaries(minXY_x, maxXY_x, BoundaryMode.FIXED);
 				mySimpleXYPlot.redraw();
 			}
 			break;
 		}
 		return true;
 	}

 	private void zoom(float scale) {
 		long domainSpan = maxXY_x - minXY_x;
 		long domainMidPoint = maxXY_x - domainSpan / 2l;
 		float offset = domainSpan * scale / 2.0f;
 		Log.d("zoom","offset: "+offset);
 		minXY_x= domainMidPoint-(long)offset;
 		maxXY_x= domainMidPoint+(long)offset;
 	}

 	private void scrollX(float pan) {
 		float domainSpan = maxXY_x	- minXY_x;
 		float step = domainSpan / mySimpleXYPlot.getWidth();
 		float offset = pan * step;
 		minXY_x+= (long)offset;
 		maxXY_x+= (long)offset;
 	}

 	private void scrollY(float pan) {
 		float domainSpan = maxXY_y	- minXY_y;
 		float step = domainSpan / mySimpleXYPlot.getHeight();
 		Log.d("PlayerStatsActivity","Step: "+step+", domainStep: "+domainSpan);
 		float offset = pan * step;
 		minXY_y-= offset;
 		maxXY_y-= offset;
 	}

 	private float spacing(MotionEvent event) {
 		float x = event.getX(0) - event.getX(1);
 		float y = event.getY(0) - event.getY(1);
 		return (float) Math.sqrt(x * x + y * y);
 	}    

}